package com.seata.demo.cloud.datasource;

import cn.hutool.core.util.StrUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

@Aspect
@Order(-10)
@Component
public class CustomTransactionAspect {
    private static Logger logger = LoggerFactory.getLogger(CustomTransactionAspect.class);
    @Autowired
    PlatformTransactionManager transactionManager;

    /**
     * 分支事务采用其他的数据源处理
     * @param joinPoint
     * @param customTransaction
     * @return
     * @throws Throwable
     */
    @Around("@annotation(customTransaction)")
    public Object doTransaction(ProceedingJoinPoint joinPoint, CustomTransaction customTransaction) throws Throwable{
        String oldDataSourceType = DynamicDataSourceHolder.getDataSourceType();
        String curDataSourceType = customTransaction.dataSource();
        if(StrUtil.isEmpty(curDataSourceType)||(!DynamicDataSourceHolder.containsDataSource(curDataSourceType))){
            //没有配置,走默认
            curDataSourceType = DynamicDataSource.PRIMARY_DATA_SOURCE;
        }
        if(!curDataSourceType.equals(oldDataSourceType)){
            DefaultTransactionDefinition def = new DefaultTransactionDefinition();
            DynamicDataSourceHolder.setDataSourceType(curDataSourceType);
            if(!customTransaction.readOnly()){
                def.setIsolationLevel(customTransaction.isolation());
                def.setPropagationBehavior(customTransaction.propagation());
                TransactionStatus status = transactionManager.getTransaction(def);
                try{
                    Object [] args = joinPoint.getArgs();
                    Object result = joinPoint.proceed(args);
                    transactionManager.commit(status);
                    return result;
                }catch (Throwable ex){
                    logger.error("自定义事务执行失败",ex);
                    transactionManager.rollback(status);
                    throw ex;
                }finally {
                    DynamicDataSourceHolder.setDataSourceType(oldDataSourceType);
                }
            }
        }
        //其他情况直接执行
        Object [] args = joinPoint.getArgs();
        Object result = joinPoint.proceed(args);
        return result;
    }
}
